package client.view;

import client.comms.PostData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigInteger;
import java.net.URL;
import java.util.ArrayList;
import java.util.Vector;
import java.security.*;

/**
 * Created by IntelliJ IDEA.
 * User: sam
 * Date: 07/04/12
 * Time: 16:02
 * To change this template use File | Settings | File Templates.
 */
public class RepositoriesPanel extends JPanel implements ActionListener {

    //JTabbedPane tabbedPane;
    //JMenuBar menuBar;
    //JMenu menu;
    //JMenuItem menuItem1;
    //JMenuItem menuItem2;

    JComboBox repositoryList;
    JTextField usernameField;
    JPasswordField passwordField;
    Vector repositoryData;
    RepositoriesPanel instance;
    DownloadControlPanel downloadControlPanel;
    SettingsPanel settingsPanel;
    JTabbedPane mfWindowTabbedPane;

    // has a DownloadResultsPanel to populate Genres when login successful

    public RepositoriesPanel(DownloadControlPanel downloadControlPanel, SettingsPanel settingsPanel, JTabbedPane mfWindowTabbedPane) {

        instance = this;

        this.downloadControlPanel = downloadControlPanel;
        this.settingsPanel = settingsPanel;
        this.mfWindowTabbedPane = mfWindowTabbedPane;

        ReportsPanel.log("RepositoriesPanel(), downloadControlPanel "+this.downloadControlPanel);

        setLayout(new GridLayout(1,2));

        Border lineBorder = BorderFactory.createEtchedBorder();

        JPanel signInPanel = new JPanel();
        JPanel signInContentPanel = new JPanel();

        //signInPanel.setBorder(lineBorder);
        signInPanel.setLayout(new BoxLayout(signInPanel, BoxLayout.Y_AXIS));

        JPanel signInHeaderPanel = new JPanel();

        JLabel signInHeaderLabel = new JLabel("Sign-in");

        //signInHeaderLabel.setPreferredSize(new Dimension(245,25));

        Color signInColor = new Color(204,0,102);

        URL resourceURL = getClass().getClassLoader().getResource(MFWindow.MEDIA+"access_icon.png");
        Icon tmpIcon = new ImageIcon(resourceURL);
        signInHeaderLabel.setIcon(tmpIcon);
        //signInHeaderLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
        //signInHeaderLabel.setPreferredSize(new Dimension(285, 25));
        //signInHeaderLabel.setOpaque(true);
        signInHeaderLabel.setForeground(signInColor);
        signInHeaderLabel.setFont(new Font(signInHeaderLabel.getFont().getName(), Font.BOLD, signInHeaderLabel.getFont().getSize() + 1));
        //signInHeaderLabel.setBackground(new Color(204, 204, 204));
        //signInHeaderLabel.setBorder(lineBorder);

        // ------------------------------------------------

        JPanel createPanel = new JPanel();

        createPanel.setLayout(new BoxLayout(createPanel, BoxLayout.Y_AXIS));
        //createPanel.setLayout(new GridLayout(1,1));
        createPanel.setBorder(lineBorder);

        JLabel createHeaderLabel = new JLabel("Create");
        resourceURL = getClass().getClassLoader().getResource(MFWindow.MEDIA+"create_repo_icon.png");
        tmpIcon = new ImageIcon(resourceURL);
        createHeaderLabel.setIcon(tmpIcon);
        Color createColor = new Color(51,153,71);

        JPanel createHeaderPanel = new JPanel();

        createHeaderLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
        createHeaderLabel.setPreferredSize(new Dimension(285,25));
        createHeaderLabel.setOpaque(true);
        createHeaderLabel.setForeground(createColor);
        createHeaderLabel.setFont(new Font(createHeaderLabel.getFont().getName(),Font.BOLD,createHeaderLabel.getFont().getSize()+1));
        createHeaderLabel.setBackground(new Color(204,204,204));
        createHeaderLabel.setBorder(lineBorder);

        createHeaderPanel.add(createHeaderLabel);

        JPanel createContentPanel = new JPanel();

        createPanel.add(createHeaderPanel);
        createPanel.add(createContentPanel);

        resourceURL = getClass().getClassLoader().getResource(MFWindow.MEDIA+"ftp_icon.png");
        tmpIcon = new ImageIcon(resourceURL);

        JPanel ftpPanel = new JPanel();
        JLabel ftpLabel = new JLabel("Host");
        ftpLabel.setIcon(tmpIcon);
        JTextField ftpField = new JTextField("ftp://");

        ftpPanel.setLayout(new BoxLayout(ftpPanel, BoxLayout.Y_AXIS));
        ftpPanel.add(ftpLabel);
        ftpPanel.add(ftpField);

        JPanel authPanel = new JPanel();
        JLabel authLabel = new JLabel("Authentication");
        //ftpLabel.setIcon(tmpIcon);
        JTextField userField = new JTextField("");
        JTextField pwdField = new JTextField("");

        authPanel.setLayout(new BoxLayout(authPanel, BoxLayout.Y_AXIS));
        authPanel.add(authLabel);
        authPanel.add(userField);
        authPanel.add(pwdField);

        //createPanel.add(ftpPanel);
        //createPanel.add(authPanel);

        // ----------------------------------------------------


        Dimension loginPanelGap = new Dimension(10,5);

        JLabel listLabel = new JLabel("Repository:");
        JLabel usernameLabel = new JLabel("Username:");
        JLabel passwordLabel = new JLabel("Password:");

        JButton loginBtn = new JButton("Login");

        resourceURL = getClass().getClassLoader().getResource(MFWindow.MEDIA+"lock_icon.png");
        tmpIcon = new ImageIcon(resourceURL);
        loginBtn.setIcon(tmpIcon);

        Border bevelBorder = BorderFactory.createBevelBorder(BevelBorder.LOWERED);

        usernameField = new JTextField();
        usernameField.setBorder(bevelBorder);

        passwordField = new JPasswordField(20);
        passwordField.setBorder(bevelBorder);
        passwordField.setName("PasswordField");
        passwordField.addActionListener(this);

        usernameField.setText("Sam");
        passwordField.setText("test123");

        Dimension d1 = new Dimension(200, 20);
        usernameField.setMaximumSize(d1);
        passwordField.setMaximumSize(d1);

        //usernameField.setMaximumSize(new Dimension(50, 25));

        repositoryData = new Vector();
        repositoryList = new JComboBox();
        repositoryList.setMaximumSize(new Dimension(245,25));
        repositoryList.setModel(new DefaultComboBoxModel(repositoryData));

        // TODO remove forcing of selected index 0.. tmp while there is only 1 repository
        //repositoryList.setSelectedIndex(0);


        EmptyBorder padding = (EmptyBorder) BorderFactory.createEmptyBorder(20, 0, 0, 0);

                                //top
                                 //left
                                 //bottom
                                //right

        JPanel usernamePanel = new JPanel();
        JPanel passwordPanel = new JPanel();
        JPanel repositoryPanel = new JPanel();
        JPanel loginBtnPanel = new JPanel();

        signInHeaderPanel.setBorder(padding);
        //repositoryPanel.setBorder(lineBorder);
        //usernamePanel.setBorder(lineBorder);
        //passwordPanel.setBorder(lineBorder);
        //loginBtnPanel.setBorder(lineBorder);

        JPanel gapPanel = new JPanel();
        gapPanel.add(Box.createRigidArea(loginPanelGap));
        gapPanel.setBorder(lineBorder);

        signInHeaderPanel.setLayout(new BoxLayout(signInHeaderPanel, BoxLayout.Y_AXIS));
        repositoryPanel.setLayout(new BoxLayout(repositoryPanel,BoxLayout.Y_AXIS));
        usernamePanel.setLayout(new BoxLayout(usernamePanel,BoxLayout.Y_AXIS));
        passwordPanel.setLayout(new BoxLayout(passwordPanel,BoxLayout.Y_AXIS));
        loginBtnPanel.setLayout(new BoxLayout(loginBtnPanel,BoxLayout.Y_AXIS));

        signInHeaderLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        signInHeaderLabel.setAlignmentY(Component.CENTER_ALIGNMENT);

        //signInHeaderLabel.setVerticalAlignment(JLabel.CENTER);//SwingConstants.CENTER);

        //signInHeaderLabel.setVerticalTextPosition(JLabel.CENTER);

        signInHeaderPanel.setAlignmentY(SwingConstants.CENTER);
        signInHeaderPanel.add(signInHeaderLabel);
        //signInHeaderPanel.setBorder(lineBorder);

        usernameLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        usernameField.setAlignmentX(Component.CENTER_ALIGNMENT);

        usernamePanel.add(usernameLabel);
        usernamePanel.add(usernameField);

        passwordLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        passwordField.setAlignmentX(Component.CENTER_ALIGNMENT);

        passwordPanel.add(passwordLabel);
        passwordPanel.add(passwordField);

        listLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        repositoryList.setAlignmentX(Component.CENTER_ALIGNMENT);

        repositoryPanel.add(listLabel);
        repositoryPanel.add(repositoryList);

        loginBtn.setAlignmentX(Component.CENTER_ALIGNMENT);
        loginBtnPanel.add(loginBtn);

        signInContentPanel.setLayout(new GridLayout(5,1));
        //signInContentPanel.add(gapPanel);
        signInContentPanel.add(signInHeaderPanel);
        signInContentPanel.add(repositoryPanel);
        signInContentPanel.add(usernamePanel);
        signInContentPanel.add(passwordPanel);
        signInContentPanel.add(loginBtnPanel);
        //signInContentPanel.add(Box.createRigidArea(new Dimension(245,80)));

        //signInContentPanel.pack();

        signInPanel.add(signInContentPanel);

        add(signInPanel);
        add(createPanel);

        loginBtn.addActionListener(this);
    }

    public void init() {
        //Warning first Server contact with no user initiation - pop / lock rest of UI etc ??????
        //go to this Panel first after user launches Music-alms?

        //JOptionPane.showMessageDialog(this,"Retrieving Repositories", "Info", JOptionPane.INFORMATION_MESSAGE);

        getRepositoryList();
    }

    public void getRepositoryList() {

        ReportsPanel.log("Retrieving Music-alms respositories...");

        StringBuilder strReq = new StringBuilder();

        strReq.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>"+"\n");
        strReq.append("<MFRequest>"+"\n");
        strReq.append("<Request type='Repositories' data=''/>"+"\n");
        strReq.append("</MFRequest>"+"\n");

        PostData postData = new PostData();

        Document repositoryResponse = postData.sendDataForWriteReponse(strReq.toString());

        // repositoryData

        /** <?xml version="1.0" encoding="ISO-8859-1"?>
            <MFResponse>
                <Response type='Repositories'>
                    <Repository name='Brunos Essential Music' creator='' num_genres='' num_songs='' members=''/>
                </Response>
            </MFResponse>
         */

        NodeList nList = repositoryResponse.getElementsByTagName("Response");
        Node nNode = nList.item(0);
        Element eElement = (Element) nNode;
        String type = eElement.getAttribute("type");

        if(type.equals("Error")) {

            ReportsPanel.log("Unknown server error");

            String errorCode = eElement.getAttribute("code");

                    if(errorCode.equals("ERROR_WITH_MF_SERVER")) {

                       JOptionPane.showMessageDialog(this,"Server Error: Unable to retrieve repositories.", "Error", JOptionPane.ERROR_MESSAGE);
                    }

        } else if(type.equals("Repositories") ) {

            nList = repositoryResponse.getElementsByTagName("Repository");
            nNode = nList.item(0);
            eElement = (Element) nNode;

            for (int i = 0; i < nList.getLength(); i++) {
                nNode = nList.item(i);
                if (nNode.getNodeType() == Node.ELEMENT_NODE) {
                    eElement = (Element) nNode;
                    eElement.normalize();
                    String tmpReposName = eElement.getAttribute("name");

                    ReportsPanel.log(i +"] "+tmpReposName);

                    repositoryData.add(tmpReposName);
                }
            }

            // TODO can we just call an "update" method??
            repositoryList.setModel(new DefaultComboBoxModel(repositoryData));
            // repositoryList.setSelectedIndex(0);
        }
    }

    public void actionPerformed(ActionEvent actionEvent) {

        String strAction = actionEvent.getActionCommand();
        Object eventSrc = actionEvent.getSource();

        ReportsPanel.log("actionPerformed "+strAction);
        ReportsPanel.log("eventSrc "+eventSrc);

        if(strAction == "Login" || eventSrc.equals(passwordField)) {
            loginUser();
        }

        /*else if(eventSrc.equals(passwordField)) {
            //JOptionPane optionPane = new JOptionPane("Are you sure you want to save current settings?", JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION);
            //JDialog dialog = optionPane.createDialog(null, "Manual Creation");
            //dialog.setVisible(true);

            int confirm = JOptionPane.showOptionDialog(instance, "Are you sure you want to save current settings?", "Exit Confirmation", JOptionPane.YES_NO_OPTION, JOptionPane.YES_NO_OPTION,null,null,null);

            // yes = 0, no = 1

            if(confirm == 0 ) {
                loginUser();
            }
        }*/
    }

    private void loginUser(){

        //TODO encrypt password

        String tmpUsername = usernameField.getText();
        String tmpPassword;
	    tmpPassword = passwordField.getText();
	    int selectedIndex = repositoryList.getSelectedIndex();

        ReportsPanel.log("selectedIndex "+selectedIndex);
        String repositoryName;
	    repositoryName = (String) repositoryData.get(selectedIndex);

	    // Should never happen because 0 is dft selected index

        if(repositoryName != null && repositoryName != "") {

        }

        ReportsPanel.log("repositoryName "+repositoryName);

        if(tmpPassword.length() > 0 && tmpPassword != null && tmpUsername.length() > 0 && tmpUsername != null)
        {
            String md5 = null;

            try {

                // WARNING!!!!!!!!!!! Base is different. The MySQL MD5 result is in base-16, while the Java MD5 is in base-10.
                // update mf_users set password=MD5('test123') where name='Sam';

                String sessionid = tmpUsername;

                //byte[] defaultBytes = sessionid.getBytes();

                MessageDigest algorithm = MessageDigest.getInstance("MD5");

                //algorithm.reset();

                // ------------ solution 0 -------------------

                //md5 = org.apache.commons.codec.digest.DigestUtils.md5Hex(sessionid);

                md5 = convertToMySQLMD5(sessionid);
                //ReportsPanel.log(md5);

                // ------------ solution 1 -------------------
                //algorithm.update(sessionid.getBytes(), 0, sessionid.length());
                //md5 = new BigInteger(1, algorithm.digest()).toString(16);


                //------------- solution 2 -------------------

                //algorithm.update(defaultBytes);

	            //byte messageDigest[] = algorithm.digest();

                //StringBuffer hexString = new StringBuffer();

                //for (int i=0;i<messageDigest.length;i++) {

                    //hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
                //}

                //String foo = messageDigest.toString();

                //ReportsPanel.log("sessionid "+sessionid+" md5 version is "+hexString.toString());

                ReportsPanel.log("sessionid "+sessionid+" md5 version is "+md5);

                /**
                 *  +----+------+---------------------+----------------------------------+
                    | id | name | registered          | password                         |
                    +----+------+---------------------+----------------------------------+
                    |  1 | Sam  | 2012-06-02 16:42:17 | cc03e747a6afbbcbf8be7668acfebee5 |
                    +----+------+---------------------+----------------------------------+
                 */

            // but test123 with above MD5: sessionid Sam md5 version is baecde1bf72c28d435c89a66afc61a

            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }

            //TODO should really encrypt pwd to MD5 too
            //TODO repository attribute never used

            StringBuilder strReq = new StringBuilder();

            ReportsPanel.log("user: "+tmpUsername);
            ReportsPanel.log("encryption: "+md5);
            ReportsPanel.log("respository: "+repositoryName);

            strReq.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>"+"\n");
                strReq.append("<MFRequest>"+"\n");
                    strReq.append("<Request type='Login' data=''/>"+"\n");
                    strReq.append("<Login username='"+tmpUsername+"' password='"+tmpPassword+"' respository='"+repositoryName+"'/>"+"\n");
            strReq.append("</MFRequest>"+"\n");

            PostData postData = new PostData();
            Document loginResp = postData.sendDataForWriteReponse(strReq.toString());

            NodeList nList = loginResp.getElementsByTagName("Response");
            Node nNode = nList.item(0);
            Element eElement = (Element) nNode;
            String type = eElement.getAttribute("type");

            ReportsPanel.log("Login response: "+type);

                /**
                 * <MFResponse>
                 *     <Response type='Error' code='MF_USER_NOT_FOUND'>
                 *         </Response>
                 * </MFResponse>
                 */

                if(type.equals("Error")) {
                    String errorCode = eElement.getAttribute("code");

                    if(errorCode.equals("MF_USER_NOT_FOUND")) {
                       ReportsPanel.log("Login error: user details not found ");
                       JOptionPane.showMessageDialog(this,"Invalid login details or repository.", "Error", JOptionPane.ERROR_MESSAGE);
                    } else {
                        ReportsPanel.log("Login error: unknown error");
                    }
                } else if(type.equals("Login")) {

                    ReportsPanel.log("Login successful.  Genre list:");

                    mfWindowTabbedPane.setSelectedIndex(1);
                    usernameField.setText("");
                    passwordField.setText("");

                    // TODO session id not actually needed, just passed for debugging

                    // nList = loginResp.getElementsByTagName("Login");

                    /**
                     * <?xml version="1.0" encoding="ISO-8859-1"?>
                        <MFResponse>
                            <Response type='Login'>
                            <Login name='Sam' session='CF66F005071BD0BC4F0B4D089A4F191A'/>

                                                <Genre name='Rock' num_entries='349' updated='02/25/2012' description='American pop, British rock, etc'/>
                                                 <Genre name='Dance' num_entries='349' updated='02/25/2012' description='Happy, cheesy, epic, any dance tracks'/>
                                                 <Genre name='Folk' num_entries='349' updated='02/25/2012' description='Irish, African, anything oldy'/>
                                                 <Genre name='Drum and bass' num_entries='349' updated='02/25/2012' description='Classic old school beats plus anthemic dandb'/>
                                                 <Genre name='Ambient' num_entries='349' updated='02/25/2012' description='Chill out beats and trip hop stuff'/>
                                                 <Genre name='Rave and Techno' num_entries='349' updated='02/25/2012' description='Eastern European to Detroit beats'/>
                                                 <Genre name='Hip Hop' num_entries='349' updated='02/25/2012' description='Urban youth culture associated with rap'/>
                                                 <Genre name='Dub' num_entries='349' updated='02/25/2012' description='Old school or new school dub'/>
                                                 <Genre name='asfsadfasf' num_entries='349' updated='03/25/2012' description='some cool music'/>
                                                 <Genre name='kkkkkkk' num_entries='349' updated='03/25/2012' description='some cool music'/>
                                                 <Genre name='sam' num_entries='349' updated='03/25/2012' description='some cool music'/>
                                                 <Genre name='dder' num_entries='349' updated='03/25/2012' description='some cool music'/>
                                                 <Genre name='new' num_entries='349' updated='03/25/2012' description='some cool music'/>
                                                 <Genre name='llllllllll' num_entries='349' updated='03/25/2012' description='lllllllllll'/>
                                                 <Genre name='hjkl' num_entries='349' updated='03/25/2012' description='hjlljh'/>
                                                 <Genre name='test' num_entries='349' updated='03/28/2012' description='test'/>
                                                 <Genre name='sams genre' num_entries='349' updated='04/29/2012' description='cool music only'/>

                            <UserSettings download_dir='../' email_notify='no' auto_open='no' clear_uploads='no' decompress='no'/>
                            </Response>
                        </MFResponse>
                     */

                // singles out
                // nList = genreResponse.getElementsByTagName("Genre");
                // when parsing so ok to give it all of XML

                downloadControlPanel.populateGenreTable(loginResp);

                    // Just hacky. Could have passed in reference, but too many panel refs flying about so
                    // so wen static property route.

                    // Also - potentially many diff areas / panels need this info
                    // so makes sense to make it static/global

                nList = loginResp.getElementsByTagName("UserSettings");
                nNode = nList.item(0);
                eElement = (Element) nNode;

                SettingsPanel.USER_SETTING_AUTO_OPEN = eElement.getAttribute("auto_open");
                SettingsPanel.USER_SETTING_CLEAR_UPLOADS = eElement.getAttribute("clear_uploads");
                SettingsPanel.USER_SETTING_DECOMPRESS = eElement.getAttribute("decompress");
                SettingsPanel.USER_SETTING_DOWNLOAD_DIR = eElement.getAttribute("download_dir");
                SettingsPanel.USER_SETTING_EMAIL_NOTIFY = eElement.getAttribute("email_notify");

                settingsPanel.updateUserPreferences();

                ReportsPanel.log("USER_SETTING_AUTO_OPEN "+SettingsPanel.USER_SETTING_AUTO_OPEN);
                ReportsPanel.log("USER_SETTING_CLEAR_UPLOADS "+SettingsPanel.USER_SETTING_CLEAR_UPLOADS);
                ReportsPanel.log("USER_SETTING_DECOMPRESS "+SettingsPanel.USER_SETTING_DECOMPRESS);
                ReportsPanel.log("USER_SETTING_DOWNLOAD_DIR "+SettingsPanel.USER_SETTING_DOWNLOAD_DIR);
                ReportsPanel.log("USER_SETTING_EMAIL_NOTIFY "+SettingsPanel.USER_SETTING_EMAIL_NOTIFY);

                //JOptionPane.showMessageDialog(this,"You are now logged in to Music-alms.", "Info", JOptionPane.INFORMATION_MESSAGE);

                }
        } else {
            ReportsPanel.log("No username or pwd provided");
            JOptionPane.showMessageDialog(this,"Enter a username & password to login.", "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

    public static String convertToMySQLMD5(String input) throws NoSuchAlgorithmException {
    String result = input;
    if(input != null) {
        MessageDigest md = MessageDigest.getInstance("MD5"); //or "SHA-1"
        md.update(input.getBytes());
        BigInteger hash = new BigInteger(1, md.digest());
        result = hash.toString(16);
        while(result.length() < 32) {
            result = "0" + result;
        }
    }
    return result;
}
}
